#include "stdafx.h"
//-------------------------------------------------------------------------------------------------
//ArchiveProcGUIView.cpp : implementation of the CArchiveProcGUIView class       
//-------------------------------------------------------------------------------------------------
//FreeBSD License
//Copyright 2011 Will Stott All rights reserved.
//
//Redistribution and use in source and binary forms, with or without modification, are
//permitted provided that the following conditions are met:
//
//   1. Redistributions of source code must retain the above copyright notice, this list of
//      conditions and the following disclaimer.
//
//   2. Redistributions in binary form must reproduce the above copyright notice, this list
//      of conditions and the following disclaimer in the documentation and/or other materials
//      provided with the distribution.
//
//THIS SOFTWARE IS PROVIDED BY Will Stott ``AS IS'' AND ANY EXPRESS OR IMPLIED
//WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
//FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Will Stott OR
//CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
//CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
//SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
//ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
//ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//The views and conclusions contained in the software and documentation are those of the
//authors and should not be interpreted as representing official policies, either expressed
//or implied, of Will Stott.
//
//----Authors--------------------------------------------------------------------------------------
//created by: will.stott@ucl.ac.uk July 2011
//
//----Comments-------------------------------------------------------------------------------------
//
//-------------------------------------------------------------------------------------------------


// SHARED_HANDLERS can be defined in an ATL project implementing preview, thumbnail
// and search filter handlers and allows sharing of document code with that project.
#ifndef SHARED_HANDLERS
#include "ArchiveProcGUI.h"
#endif

#include "MainFrm.h"
#include "ArchiveProcGUIDoc.h"
#include "ArchiveProcGUIView.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CArchiveProcGUIView

IMPLEMENT_DYNCREATE(CArchiveProcGUIView, CTreeView)

BEGIN_MESSAGE_MAP(CArchiveProcGUIView, CTreeView)
	// Standard printing commands
	ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CArchiveProcGUIView::OnFilePrintPreview)
	ON_WM_CONTEXTMENU()
	ON_WM_RBUTTONUP()
	ON_WM_CREATE()
	ON_NOTIFY_REFLECT(TVN_SELCHANGED, &CArchiveProcGUIView::OnTvnSelchanged)
	ON_COMMAND(ID_VIEW_REFRESH, &CArchiveProcGUIView::OnViewRefresh)
	ON_UPDATE_COMMAND_UI(ID_VIEW_REFRESH, &CArchiveProcGUIView::OnUpdateViewRefresh)
END_MESSAGE_MAP()

// CArchiveProcGUIView construction/destruction

CArchiveProcGUIView::CArchiveProcGUIView() : 
	m_hImageSelected('\0'),
	m_hRoot('\0'),
	m_ErrorRecoveryInProgress(false),
	m_InitialUpdateDone(false)
{
	// TODO: add construction code here
//!!!!!!!!!!!!!!!
#ifdef _DEBUG
	MxUtils::OutputDebugMsg("CArchiveProcGUIView::CArchiveProcGUIView()", "tree view ctor");
#endif
//!!!!!!!!!!!!!!!

}

CArchiveProcGUIView::~CArchiveProcGUIView()
{
//!!!!!!!!!!!!!!!
#ifdef _DEBUG
	MxUtils::OutputDebugMsg("CArchiveProcGUIView::~CArchiveProcGUIView", "tree view dtor");
#endif
//!!!!!!!!!!!!!!!
}

BOOL CArchiveProcGUIView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs
	cs.style = cs.style | TVS_HASLINES ;

	return CTreeView::PreCreateWindow(cs);
}

// CArchiveProcGUIView drawing

void CArchiveProcGUIView::OnDraw(CDC* /*pDC*/)
{
	CArchiveProcGUIDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	// TODO: add draw code for native data here
}


// CArchiveProcGUIView printing


void CArchiveProcGUIView::OnFilePrintPreview()
{
#ifndef SHARED_HANDLERS
	AFXPrintPreview(this);
#endif
}

BOOL CArchiveProcGUIView::OnPreparePrinting(CPrintInfo* pInfo)
{
	// default preparation
	return DoPreparePrinting(pInfo);
}

void CArchiveProcGUIView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add extra initialization before printing
}

void CArchiveProcGUIView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add cleanup after printing
}

void CArchiveProcGUIView::OnRButtonUp(UINT /* nFlags */, CPoint point)
{
	ClientToScreen(&point);
	OnContextMenu(this, point);
}

void CArchiveProcGUIView::OnContextMenu(CWnd* /* pWnd */, CPoint point)
{
#ifndef SHARED_HANDLERS
	theApp.GetContextMenuManager()->ShowPopupMenu(IDR_POPUP_EDIT, point.x, point.y, this, TRUE);
#endif
}

// CArchiveProcGUIView diagnostics

#ifdef _DEBUG
void CArchiveProcGUIView::AssertValid() const
{
	CView::AssertValid();
}

void CArchiveProcGUIView::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}

CArchiveProcGUIDoc* CArchiveProcGUIView::GetDocument() const // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CArchiveProcGUIDoc)));
	return (CArchiveProcGUIDoc*)m_pDocument;
}
#endif //_DEBUG


// CArchiveProcGUIView message handlers


int CArchiveProcGUIView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	int rc = -1;
//!!!!!!!!!!!!!!!
#ifdef _DEBUG
	MxUtils::OutputDebugMsg("CArchiveProcGUIView:::OnCreate()", "create tree");
#endif
//!!!!!!!!!!!!!!!

	if (CTreeView::OnCreate(lpCreateStruct) == -1)
		CArchiveProcGUIApp::UserErrorMsg("Fatal Error", "unable to create tree", "unable to recover", "restart application", MB_ICONSTOP | MB_OK );
	else
	{
		if ( m_TreeImages.Create(IDB_TREEVIEWICONS, 16, 1, RGB(255, 255, 255)))
		{
			GetTreeCtrl().SetImageList(&m_TreeImages, TVSIL_NORMAL);
			rc = 0;
		}
	}
	return rc;
}


void CArchiveProcGUIView::OnInitialUpdate()
{
	bool rc = false;
//!!!!!!!!!!!!!!!
#ifdef _DEBUG
	MxUtils::OutputDebugMsg("CArchiveProcGUIView:::OnInitialUpdate()", "call ResetTree() and do CTreeView::OnInitialUpdate()");
#endif
//!!!!!!!!!!!!!!!

	ResetTree();

	CTreeView::OnInitialUpdate();

	m_InitialUpdateDone = true;
}

void CArchiveProcGUIView::OnActivateView(BOOL bActivate, CView* pActivateView, CView* pDeactiveView)
{
	bool ChangeDoc = false;
	CMainFrame *pMainFrame = dynamic_cast<CMainFrame *>(AfxGetMainWnd());
	if ( (pMainFrame != '\0') && (pMainFrame->IsKindOf(RUNTIME_CLASS(CMainFrame))))
	{
		CArchiveProcGUIDoc *pDoc = CArchiveProcGUIDoc::GetActiveDoc();
		if (pMainFrame->IsSelectedDoc(pDoc) == false)
		{
			ChangeDoc = true;
			pMainFrame->SetSelectedDoc(pDoc);
		}
	}

//!!!!!!!!!!!!!!!
#ifdef _DEBUG
	MxUtils::OutputDebugMsg("CArchiveProcGUIView::OnActivateView()", "change doc=%d: view activate=%d,(pActivateView == pDeactiveView)=%d", ChangeDoc, bActivate,  (pActivateView == pDeactiveView) ? 1 : 0 );
#endif
//!!!!!!!!!!!!!!!

	CTreeView::OnActivateView(bActivate, pActivateView, pDeactiveView);

	if ( bActivate )
	{
		if ((pActivateView != pDeactiveView) || (ChangeDoc == true))
			OnViewRefresh();
	}
}

void CArchiveProcGUIView::OnUpdateViewRefresh(CCmdUI *pCmdUI)
{
	pCmdUI->Enable(TRUE);
}

void CArchiveProcGUIView::OnViewRefresh()
{

//!!!!!!!!!!!!!!!
#ifdef _DEBUG
	MxUtils::OutputDebugMsg("CArchiveProcGUIView::::OnViewRefresh()", "refresh UI using image currently selected in tree");
#endif
//!!!!!!!!!!!!!!!

	if (m_hRoot != '\0')
	{
		const char *errMsg = '\0';

		HTREEITEM hImageSel = NULL;
		if ( (hImageSel = GetTreeCtrl().GetSelectedItem()) == NULL )
			errMsg = "no image selected in tree control";
		else
			errMsg = DoImageSelection(hImageSel);

		if ( errMsg != '\0')
			DoErrorRecovery("internal error", errMsg, "click a different image item and try again" );
	}
}

void CArchiveProcGUIView::OnUpdate(CView* pSender, LPARAM lHint, CObject *pHint)
{
	CArchiveProcGUIDoc *pDoc = GetDocument();
	ASSERT(pDoc != NULL);
//!!!!!!!!!!!!!!!
#ifdef _DEBUG
	MxUtils::OutputDebugMsg("CArchiveProcGUIView::OnUpdate()", "m_InitialUpdateDone=%d, pSender=%s, lHint=%s, pHint%s", m_InitialUpdateDone, CArchiveProcGUIApp::GetRunTimeTypeName(pSender), CArchiveProcGUIDoc::GetUpdateHintStr(lHint), (pHint == '\0') ? "==NULL" : "!=NULL");
#endif
//!!!!!!!!!!!!!!!

	if ( m_InitialUpdateDone )
	{
		const char *errMsg = '\0';
		const char *errType = '\0';

		if (lHint == CArchiveProcGUIDoc::UpdateAllViewsOpenDoc)
		{
			if ( DoLoadImagesFromDocument() == false)
				errType = "user error", errMsg = "Unable to load images from document";
		}
		else if (lHint == CArchiveProcGUIDoc::UpdateAllViewsSetNewImage )		//CImageForm::OnInitialUpdate() calls pDoc->UpdateAllViews(this, CArchiveProcGUIDoc::UpdateAllViewsSetNoImage);
		{
			if (pDoc->IsValidSelectedImage() == false )
				GetTreeCtrl().SelectItem(m_hRoot);
			else
			{
				if (SelectImageItem(pDoc->GetSelImageDicomRef()) == false)
					errType = "user error", errMsg = "Dicom Ref not found in tree";
			}
		}
	
		if ( errMsg != '\0')
			DoErrorRecovery(errType, errMsg);
	}
}

void CArchiveProcGUIView::OnTvnSelchanged(NMHDR *pNMHDR, LRESULT *pResult)
{
//!!!!!!!!!!!!!!!
#ifdef _DEBUG
	MxUtils::OutputDebugMsg("CArchiveProcGUIView:::OnTvnSelchanged()", "change of image selection: get the selected tree item, get its DicomRef, then call GetDocument()->DoSelectImage");
#endif
//!!!!!!!!!!!!!!!

	if (m_hRoot != '\0')
	{
		const char *errMsg = '\0';

		LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
		if (pNMTreeView == '\0')
			errMsg = "failed to cast pNMHDR";
		else
		{
			HTREEITEM hNewImageSel = NULL;
			if ( (hNewImageSel = pNMTreeView->itemNew.hItem) == NULL)
				errMsg = "pNMTreeView->itemNew.hItem is null";
			else
				errMsg = DoImageSelection(hNewImageSel);
		}
		if ( errMsg != '\0')
			DoErrorRecovery("internal error", errMsg, "click a different image item and try again");
	}
	*pResult = 0;
}

bool CArchiveProcGUIView::SelectImageItem(const char *DicomRef)
{
	bool rc = false;
//!!!!!!!!!!!!!!!
#ifdef _DEBUG
	MxUtils::OutputDebugMsg("CArchiveProcGUIView::SelectImageItem()", "select tree item for Dicom Ref %s", DicomRef);
#endif
//!!!!!!!!!!!!!!!

	if (m_hRoot != '\0')
	{
		HTREEITEM hImage = '\0';
		HTREEITEM hFirstImage = GetTreeCtrl().GetChildItem(m_hRoot);
		if (hFirstImage != '\0')
		{
			hImage = hFirstImage;
			while (strcmp(GetDicomRef(hImage), DicomRef) != 0)
			{
				if ((hImage = GetTreeCtrl().GetNextSiblingItem(hFirstImage)) == '\0')
					break;
			}
			if (hImage != '\0')
			{
				GetTreeCtrl().SelectItem(hImage);
				rc = true;
			}
		}
	}
	return rc;
}

//-------------------------------------------------------------------------------------------------
//			Private methods
//-------------------------------------------------------------------------------------------------

const char *CArchiveProcGUIView::GetDicomRef(HTREEITEM hImage)
{
	const char *rc = '\0';

	CString ItemDicomRef(GetTreeCtrl().GetItemText(hImage));

	rc = MxUtils::WideCharsToAscii_1((LPCTSTR)ItemDicomRef);

	return rc;
}

void CArchiveProcGUIView::ResetTree()
{
//!!!!!!!!!!!!!!!
#ifdef _DEBUG
	MxUtils::OutputDebugMsg("CArchiveProcGUIView::ResetTree()", "delete all tree items and add root item");
#endif
//!!!!!!!!!!!!!!!

	m_hImageSelected = '\0';

	GetTreeCtrl().DeleteAllItems();

	m_hRoot = GetTreeCtrl().InsertItem(L"(IDF not set)", 2, 2);
	if (m_hRoot == '\0')
		CArchiveProcGUIApp::UserErrorMsg("Fatal Error", "unable to add root item of tree", "unable to recover", "restart application",  MB_ICONSTOP | MB_OK );
}

const char *CArchiveProcGUIView::DoImageSelection(HTREEITEM hNewImageSel)
{
//!!!!!!!!!!!!!!!
#ifdef _DEBUG
	MxUtils::OutputDebugMsg("CArchiveProcGUIView::DoImageSelection", "tell the rest of the application that a new tree item has been selected");
#endif
//!!!!!!!!!!!!!!!

	const char *errMsg = '\0';

	const char *DicomRef = '\0';
	if ( (hNewImageSel != m_hRoot ) && (hNewImageSel != '\0'))
	{
		if ( (DicomRef = GetDicomRef(hNewImageSel)) == '\0')
			errMsg = "MxUtils::WideCharsToAscii_1 failed, Dicom Ref is bad";
	}

	if ( GetDocument()->DoSelectImage(this, DicomRef) == false)		//bug 53 : File | Open GetDocument() here returns the old document rather than the one that has just been opened, consider CArchiveProcGUIDoc::GetActiveDoc()->DoSelectImage(...)
		errMsg = "GetDocument()->DoSelectImage() failed";
	else
		m_hImageSelected = hNewImageSel;

	return errMsg;
}

bool CArchiveProcGUIView::DoLoadImagesFromDocument()
{
	bool rc = false;

	CArchiveProcGUIDoc *pDoc = GetDocument();

//!!!!!!!!!!!!!!!
#ifdef _DEBUG
	MxUtils::OutputDebugMsg("CArchiveProcGUIView::DoLoadImagesFromDocument", "ENTER: reset tree and load image items from document: %s", ((pDoc != '\0') && (pDoc->IsIDFDocumentLoaded()) ? pDoc->GetImageDatasetFile()->GetIDFPathFileName() : "pDoc=null or pDoc->IsIDFDocumentLoaded() is false"));
#endif
//!!!!!!!!!!!!!!!

	ResetTree();
	
	if (pDoc != '\0')
	{
		if ( pDoc->GetImageDatasetFile()->GetRuntimeDir() != '\0' )
		{
			CString dir(pDoc->GetImageDatasetFile()->GetRuntimeDir());
			if ( GetTreeCtrl().SetItem(m_hRoot, TVIF_TEXT, dir, 0, 0, TVIS_BOLD, TVIS_BOLD, 0L))
			{
				TiXmlElement *child = 0;
				while( child = pDoc->GetImageDatasetFile()->IterateImages( child ) )
				{
					CString imagefile(child->GetText());
					HTREEITEM hImage = GetTreeCtrl().InsertItem((LPCTSTR)imagefile, 1, 0, m_hRoot);

				}
				//HTREEITEM hFirstImage = GetTreeCtrl().GetChildItem(m_hRoot);	//work around bug 53 
				//if ( hFirstImage )
				//{
				//	if ( GetTreeCtrl().SelectItem(hFirstImage) == TRUE)			//work around bug 53 
				//		rc = true;
				//}
			}
		}
	}
	if ( rc == false)
	{
		GetTreeCtrl().Expand(m_hRoot, TVE_EXPAND);	//work around bug 53 
		GetTreeCtrl().SelectItem(m_hRoot);
		rc = true;									//work around bug 53 
	}

//!!!!!!!!!!!!!!!
#ifdef _DEBUG
	MxUtils::OutputDebugMsg("CArchiveProcGUIView::DoLoadImagesFromDocument", "EXIT rc=%d", (rc == true) ? 1 : 0);
#endif
//!!!!!!!!!!!!!!!

	return rc;
}

void CArchiveProcGUIView::DoErrorRecovery(const char *errType, const char *errMsg, const char *suggestedAction, UINT prompt)
{
//!!!!!!!!!!!!!!!
#ifdef _DEBUG
	MxUtils::OutputDebugMsg("CArchiveProcGUIView::DoErrorRecovery()", "errType=%s, errMsg=%s, suggested action=%s m_ErrorRecoveryInProgress=%d", (errType != '\0') ? errType : "(errType is null)", (errMsg != '\0') ? errMsg : "(errMsg is null)", (suggestedAction != '\0') ? suggestedAction : "(suggestedAction is null)", m_ErrorRecoveryInProgress);
#endif
//!!!!!!!!!!!!!!!

	if ( m_ErrorRecoveryInProgress == false )
	{
		const char *errMsgRecovery = '\0';
		if ( m_hRoot == '\0')
			errMsgRecovery = "m_hRoot is null";
		else
		{
			m_ErrorRecoveryInProgress = true;
			if ( GetTreeCtrl().SelectItem(m_hRoot) == FALSE)
				errMsgRecovery = "GetTreeCtrl().SelectItem(m_hRoot) failed";
			m_ErrorRecoveryInProgress = false;
		}
		CArchiveProcGUIApp::UserErrorMsg(errType, errMsg, errMsgRecovery, suggestedAction, prompt);
	}
}



//-------------------------------------------------------------------------------------------------
//			E N D   O F   F I L E
//-------------------------------------------------------------------------------------------------












